<?php

/**
 * El supervisor define para una actividad si una transicion puede ser disparada, dispara la transicion de acuerdo a las reglas del negocio
 * actualiza el vector de marcacion, actualiza los transset
 */

require_once (BASE_DIR . 'lib/clases/pclases/workflow/engine/PDepartmentAssignation.class.php');
class PSupervisor {

	public $activity;
	public $networkRef;
	public $currentMarking;
	public $fireableTransSet;
	public $departmentSource;
	public $departmentTarget;
	public $role;
	public $user;
	public $actor;
	public $valid;
	public $error;

	function PSupervisor($activity, $fireableTransSet) {
		$m = epManager :: instance();
		$this->activity = $activity;
		$this->currentMarking = $activity->markingVector;
		$this->networkRef = $activity->networkRef;
		$this->document = $this->activity->document->variant;
		$this->fireableTransSet = $fireableTransSet;
		// select role for this trans set
		$error = 0;
		$validTS = FALSE;
		foreach ($activity->fireableTransSet as $fireable) {
			if ($fireable->epgetObjectId() == $fireableTransSet->epgetObjectId()) {
				$validTS = TRUE;
				break;
			}
		}
		if ($validTS) {
			$this->role = $this->fireableTransSet->roleRef;
			if($this->fireableTransSet->isByUser) {
				if($this->fireableTransSet->designedUser) {
					$this->user = $this->fireableTransSet->designedUser;
				}
				else {
					$validTS = FALSE;
					$error = 2;
				}
			}
		}
		else $error = 1;

		$this->valid = $validTS;
		$this->error = $error;

		return;
	}
	

	//evalua si una transicion es disparable de acuerdo a la marcacion de la red
	function isFireable($trans) {
		$m = epManager :: instance();
		$net = $this->networkRef;
		foreach ($net->transVectorInput as $vectorInput) {
			if ($trans->key == $vectorInput->index) {
				$input = $vectorInput->vector;
				break;
			}
		}
		$marking = explode('|', $this->currentMarking);
		$incidenceVector = explode('|', $input);
		$fireable = TRUE;
		for ($i = 0; $i < count($marking); $i++) {
			if ($marking[$i] < $incidenceVector[$i]) {
				$fireable = FALSE;
				break;
			}
		}
		if ($trans->type == 0) {
			if($this->user == NULL) {
				$fireable = FALSE;
			}
		}
		return $fireable;
	}

	// dispara una transicion cambiando la marcacion de la red. Cambia los transset para la nueva marcacion
	function fireTransition($trans) {
		$m = epManager :: instance();

		/*
		 * new marking, find the new current fireable trans sets
		 */

		$net = $this->networkRef;
		foreach ($net->transVectorInput as $vectorInput) {
			if ($trans->key == $vectorInput->index) {
				$input = $vectorInput->vector;
				break;
			}
		}
		foreach ($net->transVectorOutput as $vectorOutput) {
			if ($trans->key == $vectorOutput->index) {
				$output = $vectorOutput->vector;
				break;
			}
		}
		$marking = explode('|', $this->currentMarking);
		$oldMarking = $marking;
		$incidenceVector1 = explode('|', $input);
		$incidenceVector2 = explode('|', $output);
		for ($i = 0; $i < count($marking); $i++) {
			$marking[$i] += ($incidenceVector2[$i] - $incidenceVector1[$i]);
		}
		
		$this->currentMarking = implode('|', $marking);
		
		

		/*
		 * delete transSetFireable
		 */
		$this->activity->markingVector = $this->currentMarking;


		// remove old transSets
		foreach ($this->activity->fireableTransSet as $fireable) {
			    		$fireable->delete();
		}

		$fireableTransSets = $this->activity->networkRef->fireableTransSet($this->currentMarking);

		$this->activity->fireableTransSet = array ();
		// --------------------------- Conditioning new trasnset --------------------------------- //
		foreach ($fireableTransSets as $fireable) {
			$fireableTransSet = $m->create('WFireableTransSet');
			$fireableTransSet->roleRef = $fireable->transList[0]->roleRef;
			if($fireable->transList[0]->type == 0) $fireableTransSet->isByUser = TRUE;
			if($fireable->transList[0]->type == 1) $fireableTransSet->isAutomatic = TRUE;
			if($fireable->transList[0]->type == 2) $fireableTransSet->isByExternalProcess = TRUE;
			if($fireable->transList[0]->type == 3) $fireableTransSet->isByExternalProcess = TRUE;
			if($fireable->transList[0]->type == 4) $fireableTransSet->isByDate = TRUE;
			$fireableTransSet->transSet = $fireable;
			$fireableTransSet->lastDate = 0;
			$fireableTransSet->firingDate = 0;
			
			$this->activity->fireableTransSet[] = $fireableTransSet;
		}

		// ----------------------------- asign new department -------------------------- //

		$variantDoc = $this->activity->document->variant;
		$vectorSize = count($oldMarking);

		for ($i = 0; $i < $vectorSize; $i++) {
			if ($oldMarking[$i] != $marking[$i]) {
				if ($marking[$i] == 0) {
					// remove activity for the department
					foreach ($this->activity->networkRef->placeList as $place) {
						if ($place->key == $i) {
							$workingPlace = $place;
							break;
						}
					}
					foreach ($workingPlace->dptVarietyList as $dptVariety) {
						foreach ($dptVariety->variantList as $variant) {
							if ($variantDoc->epgetObjectId() == $variant->epgetObjectId()) {
								$dptName = $dptVariety->dptName;
							}
						}
					}
					$oldAssignation = new PDepartmentAssignation;
					$dpts = $m->find("FROM MDepartamento WHERE nombre = ?", $dptName);
					
					$oldAssignation->recover($this->activity, $dpts[0]);
					$oldAssignation->deleteChronogram();
				}
				if($marking[$i]>0){				
					foreach ($this->activity->networkRef->placeList as $place) {
						if ($place->key == $i) {
							$workingPlace = $place;
							break;
						}
					}
					$dptname = NULL;
					foreach ($workingPlace->dptVarietyList as $dptVariety) {
						foreach ($dptVariety->variantList as $variant) {
							if ($variantDoc->epgetObjectId() == $variant->epgetObjectId()) {
								$dptName = $dptVariety->dptName;
							}
						}
					}
										
					if($dptName != NULL) {
						$newAssignation = new PDepartmentAssignation;
						$dpts = $m->find("FROM MDepartamento WHERE nombre = ?", $dptName);
						$result = $newAssignation->receiveActivity($this->activity, $dpts[0],mktime()+20000);
						$dpts[0]->commit();
					}
				}
			}
			
		}
		$activityHist = $this->activity->history;
		$workHist = $m->create('WWorkHistory');
		

		if($this->fireableTransSet->isByUser){
			$actorList = $m->find("FROM MActor where userRef = ? and roleRef = ?", $this->user, $this->role);
			if(count($actorList) == 0){
				$actor = $m->create('MActor');
				$actor->userRef = $this->user;
				$actor->roleRef = $this->role;
			}
			else {
				$actor = $actorList[0];
			}
			$workHist->actor = $actor;
		}

		$workHist->date = mktime();
		$workHist->firedTransition = $trans;
		$workHist->activity = $activityHist;
		$workHist->commit();
		$this->activity->commit();
	}

}
?>